/*******************************************************************************
 * FilePath    : \Software\Examples\MS1656_app_UART\Src\BSP\UART.c
 * Version     : 1.0
 * Brief       : 
 * Author      : AndrewHu
 * Company     : Shanghai MacroGiga Electronics CO.,Ltd
 * Email       : Hubinbo@macrogiga.com
 * Date        : 2020-04-03 15:06:14
 * LastEditors : AndrewHu
 * LastEditTime: 2020-09-16 17:14:28
 * Description : 
 ******************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include <Includes.h>
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define MAX_SIZE 200
#define AT_CMD_MAX 100 //AT指令长度不能超过100
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef UartxHandle = {0};

u32 BaudRate = BaudRate_Def;
static u8 txBuf[MAX_SIZE], rxBuf[MAX_SIZE];
static u8 txCount = 0, rxCount = 0; //待发送、接收待取出数据的Index
static u8 txLen = 0, rxLen = 0;     //已发送、接收并取出数据的Index
static u8 rxTimeOut = 0;            //接收超时，判断串口数据是否发送完成
static u8 txEn = 0;                 //发送使能标志
/* Private function ----------------------------------------------------------*/
/* extern --------------------------------------------------------------------*/

/*******************************************************************************
 * Function    : Uart_Init
 * Brief       : 
 * Parameter   : {u32} baudRate-波特率
 * Returns     : 
 * Date        : 2020-04-03 16:53:11
 * Description : 
 ******************************************************************************/
void Uart_Init(u32 baudRate)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    u8 Istatus = GetInterfaceStatus();

    __HAL_RCC_GPIOD_CLK_ENABLE();

    GPIO_InitStruct.OpenDrain = GPIO_PUSHPULL;
    GPIO_InitStruct.Debounce.Enable = GPIO_DEBOUNCE_DISABLE;
    GPIO_InitStruct.SlewRate = GPIO_SLEW_RATE_HIGH;
    GPIO_InitStruct.DrvStrength = GPIO_DRV_STRENGTH_HIGH;
    GPIO_InitStruct.Pull = GPIO_PULLUP; //上拉

    if (Istatus == Interface_Uart0)
    {
        //PD3-RX,PD4-TX
        GPIO_InitStruct.Pin = GPIO_PIN_3; //RX
        GPIO_InitStruct.Mode = GPIO_MODE_AF;
        GPIO_InitStruct.Alternate = GPIO_AF5_UART0_RXD;
        HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

        GPIO_InitStruct.Pin = GPIO_PIN_4; //TX
        GPIO_InitStruct.Mode = GPIO_MODE_AF;
        GPIO_InitStruct.Alternate = GPIO_AF5_UART0_TXD;
        HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

        GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
        GPIO_InitStruct.Alternate = 0X00; //不复用

        GPIO_InitStruct.Pin = GPIO_PIN_5 | GPIO_PIN_6; //
        HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
    }
    else if (Istatus == Interface_Uart1)
    {
        //PD5-TX,PD6-RX
        GPIO_InitStruct.Pin = GPIO_PIN_5; //TX
        GPIO_InitStruct.Mode = GPIO_MODE_AF;
        GPIO_InitStruct.Alternate = GPIO_AF7_UART0_TXD;
        HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

        GPIO_InitStruct.Pin = GPIO_PIN_6; //TX
        GPIO_InitStruct.Mode = GPIO_MODE_AF;
        GPIO_InitStruct.Alternate = GPIO_AF7_UART0_RXD;
        HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

        GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
        GPIO_InitStruct.Alternate = 0X00; //不复用

        GPIO_InitStruct.Pin = GPIO_PIN_3 | GPIO_PIN_4; //
        HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
    }
    else
    {
        //I2C,PD5-SCL,PD6-SDA
        GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
        GPIO_InitStruct.Alternate = 0X00; //不复用

        GPIO_InitStruct.Pin = GPIO_PIN_3 | GPIO_PIN_4; //
        HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
    }

    Delay_ms(5); //延时5ms
    //判断各模式IO状态设定，防止漏电

    if (Istatus == Interface_Uart0)
    {
        //PD3-RX,PD4-TX
        if (HAL_GPIO_ReadPin(GPIOD, GPIO_PIN_5) == GPIO_PIN_RESET)
        {
            GPIO_InitStruct.Pull = GPIO_PULLDOWN; //下拉
            GPIO_InitStruct.Pin = GPIO_PIN_5;     //
            HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
        }
        if (HAL_GPIO_ReadPin(GPIOD, GPIO_PIN_6) == GPIO_PIN_RESET)
        {
            GPIO_InitStruct.Pull = GPIO_PULLDOWN; //下拉
            GPIO_InitStruct.Pin = GPIO_PIN_6;     //
            HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
        }
    }
    else
    {
        //PD5-TX,PD6-RX
        //I2C,PD5-SCL,PD6-SDA
        if (HAL_GPIO_ReadPin(GPIOD, GPIO_PIN_3) == GPIO_PIN_RESET)
        {
            GPIO_InitStruct.Pull = GPIO_PULLDOWN; //下拉
            GPIO_InitStruct.Pin = GPIO_PIN_3;     //
            HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
        }
        if (HAL_GPIO_ReadPin(GPIOD, GPIO_PIN_4) == GPIO_PIN_RESET)
        {
            GPIO_InitStruct.Pull = GPIO_PULLDOWN; //下拉
            GPIO_InitStruct.Pin = GPIO_PIN_4;     //
            HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
        }
        if (Istatus == Interface_I2C)
            return; //不开串口，返回
    }

    __HAL_RCC_UART0_CLK_ENABLE();

    UartxHandle.Instance = UART0;
    UartxHandle.Init.BaudRate = baudRate;
    UartxHandle.Init.BaudDouble = UART_BAUDDOUBLE_ENABLE;
    UartxHandle.Init.WordLength = UART_WORDLENGTH_8B;
    UartxHandle.Init.Parity = UART_PARITY_NONE;
    UartxHandle.Init.Mode = UART_MODE_TX_RX;
    HAL_UART_Init(&UartxHandle);

    //HAL_UART_Transmit_IT(&sUartxHandle, ucSendData, sizeof(ucSendData));
    //HAL_UART_Receive_IT(&sUartxHandle, ucReceiveData, sizeof(ucReceiveData));
    UART0->SCON |= UART_INTSR_RI | UART_INTSR_TI;
    HAL_NVIC_EnableIRQ(UART0_IRQn);
}
/*******************************************************************************
 * Function    : ChangeBaudRate
 * Brief       : 更改波特率
 * Parameter   : 
 * Returns     : 
 * Date        : 2020-04-03 16:52:30
 * Description : 
 ******************************************************************************/
void ChangeBaudRate(u32 bRate)
{
    BaudRate = bRate;
    Uart_Init(bRate); //初始化串口1
}
/*******************************************************************************
 * Function    : Uart_Interrupt_Enable
 * Brief       : 将RX脚改为外部中断脚
 * Parameter   :
 * Returns     :
 * Date        : 2020-04-05 23:39:50
 * Description : 当芯片进入休眠时，用RX唤醒芯片
 ******************************************************************************/
void Uart_Interrupt_Enable(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    u8 Istatus = GetInterfaceStatus();

    if ((Istatus != Interface_Uart0) && (Istatus != Interface_Uart1))
        return;             //非串口通讯方式
    ClearEnterSleepDelay(); //刚唤醒，进入休眠延时重新计时

    //UART0_RX
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.OpenDrain = GPIO_PUSHPULL;
    GPIO_InitStruct.Debounce.Enable = GPIO_DEBOUNCE_DISABLE;
    GPIO_InitStruct.SlewRate = GPIO_SLEW_RATE_HIGH;
    GPIO_InitStruct.DrvStrength = GPIO_DRV_STRENGTH_HIGH;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Alternate = 0x00; //不复用

    if (Istatus == Interface_Uart0)
        GPIO_InitStruct.Pin = GPIO_PIN_3;
    else
        GPIO_InitStruct.Pin = GPIO_PIN_6;
    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

    /* Configure Button pin as input with External interrupt */
    GPIO_InitStruct.Mode = EXTI_MODE;
    GPIO_InitStruct.Exti.Enable = GPIO_EXTI_INT_ENABLE;
    GPIO_InitStruct.Exti.EdgeLevelSel = GPIO_EXTI_INT_EDGE;
    GPIO_InitStruct.Exti.RiseFallSel = GPIO_EXTI_INT_LOWFALL;
    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

    if (Istatus == Interface_Uart0)
        __HAL_GPIO_EXTI_CLEAR_FLAG(GPIOD, GPIO_PIN_3);
    else
        __HAL_GPIO_EXTI_CLEAR_FLAG(GPIOD, GPIO_PIN_6);
    /* Enable and set Button EXTI Interrupt to the lowest priority */
    HAL_NVIC_SetPriority(GPIOD_IRQn, PRIORITY_LOW);
    HAL_NVIC_EnableIRQ(GPIOD_IRQn);
}
/*******************************************************************************
 * Function    : Uart_Interrupt_Disable
 * Brief       : 芯片通过RX唤醒后，切换为串口通讯脚
 * Parameter   :
 * Returns     :
 * Date        : 2020-04-05 23:40:58
 * Description :
 ******************************************************************************/
void Uart_Interrupt_Disable(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    u8 Istatus = GetInterfaceStatus();

    ClearEnterSleepDelay(); //刚唤醒，进入休眠延时重新计时

    HAL_NVIC_DisableIRQ(GPIOD_IRQn); //关闭IO中断

    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.OpenDrain = GPIO_PUSHPULL;
    GPIO_InitStruct.Debounce.Enable = GPIO_DEBOUNCE_DISABLE;
    GPIO_InitStruct.SlewRate = GPIO_SLEW_RATE_HIGH;
    GPIO_InitStruct.DrvStrength = GPIO_DRV_STRENGTH_HIGH;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Alternate = 0x00; //不复用

    if (Istatus == Interface_Uart0)
        GPIO_InitStruct.Pin = GPIO_PIN_3;
    else
        GPIO_InitStruct.Pin = GPIO_PIN_6;
    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

    /* Configure Button pin as input with External interrupt */
    GPIO_InitStruct.Mode = EXTI_MODE;
    GPIO_InitStruct.Exti.Enable = GPIO_EXTI_INT_DISABLE;
    GPIO_InitStruct.Exti.EdgeLevelSel = GPIO_EXTI_INT_EDGE;
    GPIO_InitStruct.Exti.RiseFallSel = GPIO_EXTI_INT_LOWFALL;
    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

    GPIO_InitStruct.Mode = GPIO_MODE_AF;
    if (Istatus == Interface_Uart0)
        GPIO_InitStruct.Alternate = GPIO_AF5_UART0_RXD;
    else
        GPIO_InitStruct.Alternate = GPIO_AF7_UART0_RXD;
    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
}
/*******************************************************************************
 * Function    : 
 * Brief       : 
 * Parameter   : 
 * Returns     : 
 * Date        : 2020-04-03 17:06:41
 * Description : 
 ******************************************************************************/
u32 GetBaudRate(void)
{
    return BaudRate;
}
/*******************************************************************************
* Function   :      UART1_IRQHandler
* Parameter  :      void
* Returns    :      void
* Description:
* Note:      :      串口1中断服务程序
*******************************************************************************/
void UartRx_Int(void)
{
    rxBuf[rxCount] = UART0->SBUF;
    rxCount++;
    if (rxCount >= MAX_SIZE)
        rxCount = 0;
    rxTimeOut = 0x00; //倒计时，判断串口数据是否接收完
}
/*******************************************************************************
* Function   :      UART1_IRQHandler
* Parameter  :      void
* Returns    :      void
* Description:
* Note:      :      串口1中断服务程序
*******************************************************************************/
void UartTx_Int(void)
{
    //还有数据未发完
    if (txCount != txLen)
    {
        UART0->SBUF = txBuf[txLen];
        //比较缓存是否溢出
        txLen++;
        if (txLen >= MAX_SIZE)
            txLen = 0x00;
    }
    else
    {
        //数据发送完成
        txEn = 0x00;
    }
}
/*******************************************************************************
* Function   :      UART1_IRQHandler
* Parameter  :      void
* Returns    :      void
* Description:
* Note:      :      串口1中断服务程序
*******************************************************************************/
void UART0_IRQHandler(void)
{
    if ((UART0->INTSR & UART_INTSR_RI) == UART_INTSR_RI)
    {
        UART0->INTCLR |= UART_INTCLR_RICLR_Msk;
        //接收
        UartRx_Int();
    }
    else if ((UART0->INTSR & UART_INTSR_TI) == UART_INTSR_TI)
    {
        UART0->INTCLR |= UART_INTCLR_TICLR_Msk;
        //发送
        UartTx_Int();
    }
}
/*******************************************************************************
 * Function    : Uart_Send_Byte
 * Brief       : 
 * Parameter   : 
 * Returns     : 
 * Date        : 2020-03-24 18:28:52
 * Description : 串口发送一个字节
 ******************************************************************************/
void Uart_Send_Byte(u8 data)
{
    txBuf[txCount] = data;
    txCount++;
    if (txCount >= MAX_SIZE)
        txCount = 0x00;
}
/*******************************************************************************
 * Function    : Uart_Send_Byte2Ascii
 * Brief       : 
 * Parameter   : {u8} data-待发送数据
 * Returns     : 
 * Date        : 2020-03-24 18:30:09
 * Description : 串口发送一个字节（转换成ASCII）
 ******************************************************************************/
void Uart_Send_Byte2Ascii(u8 data)
{
    Uart_Send_Byte(Hex2Ascii(data >> 4));
    Uart_Send_Byte(Hex2Ascii(data));
}
/*******************************************************************************
 * Function    : Uart_Send_Array
 * Brief       : 
 * Parameter   : {u8*} data-待发送数组
 * Parameter   : {u8} len-数组长度
 * Returns     : 
 * Date        : 2020-03-24 18:30:47
 * Description : 发送一个数组（原始数据）
 ******************************************************************************/
void Uart_Send_Array(u8 *data, u8 len)
{
    u8 i;
    for (i = 0; i < len; i++)
    {
        Uart_Send_Byte(data[i]);
    }
}
/*******************************************************************************
 * Function    : Uart_Send_Array_R
 * Brief       : 
 * Parameter   : {u8*} data-待发送数组
 * Parameter   : {u8} len-数组长度
 * Returns     : 
 * Date        : 2020-03-24 18:30:47
 * Description : 发送一个数组（原始数据），倒序
 ******************************************************************************/
void Uart_Send_Array_R(u8 *data, u8 len)
{
    u8 i;
    for (i = len; i != 0; i--)
    {
        Uart_Send_Byte(data[i - 1]);
    }
}
/*******************************************************************************
 * Function    : Uart_Send_Array2Ascii
 * Brief       : 
 * Parameter   : {u8*} data-待发送数组
 * Parameter   : {u8} len-数组长度
 * Parameter   : {u8} space-是否空格做间隔
 * Returns     : 
 * Date        : 2020-03-24 18:30:47
 * Description : 发送一个数组（转成ASCII）
 ******************************************************************************/
void Uart_Send_Array2Ascii(u8 *data, u8 len, u8 space)
{
    u8 i;
    for (i = 0; i < len; i++)
    {
        Uart_Send_Byte2Ascii(data[i]);
        if (space)
            Uart_Send_Byte(' '); //插入空格
    }
}
/*******************************************************************************
 * Function    : Uart_Send_Array2Ascii_R
 * Brief       : 
 * Parameter   : {u8*} data-待发送数组
 * Parameter   : {u8} len-待发送数组长度
 * Parameter   : {u8} space-是否空格做间隔
 * Returns     : 
 * Date        : 2020-03-24 18:30:47
 * Description : 发送一个数组（转成ASCII），倒序
 ******************************************************************************/
void Uart_Send_Array2Ascii_R(u8 *data, u8 len, u8 space)
{
    u8 i;
    for (i = len; i != 0; i--)
    {
        Uart_Send_Byte2Ascii(data[i - 1]);
        if (space)
            Uart_Send_Byte(' '); //插入空格
    }
}
/*******************************************************************************
 * Function    : Uart_Send_String
 * Brief       : 
 * Parameter   : {u8*} data-字符串或数组
 * Returns     : {u8} len-长度
 * Date        : 2020-03-24 18:48:47
 * Description : 发送一个字符串或数组
 ******************************************************************************/
void Uart_Send_String(u8 *data, u8 len)
{
    u8 i;
    for (i = 0; i < len; i++)
    {
        txBuf[txCount] = *(data + i);
        txCount++;
        if (txCount >= MAX_SIZE)
            txCount = 0x00;
    }
}
/*******************************************************************************
 * Function    : GetUartTxFlag
 * Brief       : 
 * Parameter   : 
 * Returns     : 
 * Date        : 2020-03-25 15:16:44
 * Description : 获取串口发送状态
 ******************************************************************************/
u8 GetUartTxFlag(void)
{
    return txEn;
}
/*******************************************************************************
 * Function    : GetUartStatus
 * Brief       : 获取串口工作状态
 * Parameter   : 
 * Returns     : 
 * Date        : 2020-03-25 15:16:44
 * Description : 
 ******************************************************************************/
u8 GetUartStatus(void)
{
    if ((txEn != 0) || (txLen != txCount) || (rxLen != rxCount))
        return 1; //串口有数据待处理
    else
        return 0; //串口空闲
}
/*******************************************************************************
 * Function    : BleSendData
 * Brief       : 
 * Parameter   : {u8} overflag-串口数据是否接收完成
 * Returns     : 
 * Date        : 2020-03-23 17:36:40
 * Description : 从串口接受数组中取出数据给蓝牙发送
 ******************************************************************************/
static void BleSendData(u8 overflag)
{
    u8 i = 0;
    u8 bleUartData[20] = {0};

    if (overflag == 0)
    {
        //数据尚未接收完
        if (rxCount >= rxLen)
        {
            if ((rxCount - rxLen) < 20)
                return; //没有达到20个字节
        }
        else
        {
            if ((MAX_SIZE - rxLen + rxCount) < 20)
                return; //没有达到20个字节
        }
    }
    //达到了20个字节，或接收完成
    while (rxCount != rxLen) //有待取出数据
    {
        bleUartData[i] = rxBuf[rxLen];
        rxLen++;
        if (rxLen >= MAX_SIZE)
            rxLen = 0;
        i++;
        if (i >= 20)
            break; //数据长度超过20，只发送20个字节
    }

    if (atcmd_Compare_uart2atcmd(bleUartData, i) == 0)
    {
        //不是切换指令
        if (GetConnectedStatus())
        {
            SendNotifyData(bleUartData, i);
            Printf_OK();
        }
        else
        {
            //蓝牙未连接
            Printf_ConnectStatus(0);
        }
    }
}
/*******************************************************************************
 * Function    : 
 * Brief       : 
 * Parameter   : {u8} overflag-串口数据是否接收完成
 * Returns     : 
 * Date        : 2020-04-06 11:29:16
 * Description : 
 ******************************************************************************/
static void BleAtCmd(u8 overflag)
{
    u8 i = 0, j = rxLen;
    u8 bleUartData[AT_CMD_MAX] = {0};

    while (rxCount != j) //有待取出数据
    {
        bleUartData[i] = rxBuf[j];
        j++;
        if (j >= MAX_SIZE)
            j = 0;

        if ((bleUartData[i] == '\n') || (bleUartData[i] == '\r'))
        {
            //找到回车换行
            if ((rxBuf[j] == '\n') || (rxBuf[j] == '\r'))
            {
                //后一个字节也是回车换行符，移除
                j++;
                if (j >= MAX_SIZE)
                    j = 0;
            }
            rxLen = j;

            AtCmdParser(bleUartData, i);
            return; //退出该函数不再向下执行
        }

        i++;
        if (i >= AT_CMD_MAX)
        {
            rxLen = j; //指令太长,丢弃
            Printf_Error(ErrorCode_NotFound);
            return; //退出该函数不再向下执行
        }
    }

    //没有找到回车换行符
    if (overflag)
    {
        rxLen = j;
        AtCmdParser(bleUartData, i);
    }
}
/*******************************************************************************
 * Function    : Uart_Send_Data
 * Brief       : 
 * Parameter   : 
 * Returns     : 
 * Date        : 2020-03-24 19:02:59
 * Description : 串口数据发送判断
 ******************************************************************************/
void Uart_Send_Data(void)
{
    if ((txLen != txCount) && (txEn == 0))
    {
        //有数据待发送，发送使能标志未置1
        //Exit2Uart();
        txEn = 1;
        UART0->SBUF = txBuf[txLen];
        txLen++;
        if (txLen >= MAX_SIZE)
            txLen = 0x00;
    }
}
/*******************************************************************************
 * Function    : Uart_Receive_Data
 * Brief       : 
 * Parameter   : 
 * Returns     : 
 * Date        : 2020-03-24 19:01:52
 * Description : 接收数据
 ******************************************************************************/
void Uart_Receive_Data(void)
{
    if (rxLen == rxCount)
    {
        rxTimeOut = 0x00;
        return; //没有接收到数据
    }

    if (rxTimeOut < 0x02) //
    {
        //串口正在接受数据
        rxTimeOut++; //串口有数据时会一直清零
        if (getBleMode())
        {
            //AT指令模式，找到回车换行符
            BleAtCmd(0);
        }
        else
        {
            //透传模式，接收到的数据超过20个字节，取出数据
            BleSendData(0);
        }
    }
    else
    {
        //串口数据接收完成，取出数据
        if (getBleMode())
        {
            //AT指令模式，接收数据完成，取出数据
            BleAtCmd(1);
        }
        else
        {
            //透传模式
            BleSendData(1);
        }
        rxTimeOut = 0x00;
    }
}
/*******************************************************************************
 * Function    : Fun_Uart_Run
 * Brief       : 
 * Parameter   : 
 * Returns     : 
 * Date        : 2020-03-24 19:02:19
 * Description : 串口执行
 ******************************************************************************/
void Fun_Uart_Run(void)
{
    Uart_Send_Data();
    Uart_Receive_Data();
}
